import sys
import platform
import logging
import subprocess

#------------------------------------------------------------------------------
# Functions used by daemon processes:

class _LogFile(object):
    """Instances of this class can be assigned to sys.stdout/stderr to
    redirect printouts to the logging module.
    """
    def __init__(self, logger=None, log_level=logging.DEBUG):
        if logger is None:
            logger = logging.getLogger()
        self.logger = logger
        self.log_level = log_level
        self.buffer = ""

    def write(self, message):
        # The logging module adds an extra newline, so split the data to write
        # by newlines and buffer the last line if it doesn't end with a
        # newline.
        lines = message.split("\n")
        if len(lines) == 1:
            self.buffer += lines[0]
            return

        self._log_line(self.buffer + lines[0])
        for line in lines[1:-1]:
            self._log_line(line)

        self.buffer = lines[-1]

    def _log_line(self, line):
        self.logger.log(self.log_level, line)

    def flush(self):
        for handler in self.logger.handlers:
            handler.flush()

_saved_stdouts = []
_saved_stderrs = []

def redirect_output_to_logger(logger=None, log_level=logging.DEBUG):
    _saved_stdouts.append(sys.stdout)
    _saved_stderrs.append(sys.stderr)
    sys.stdout = _LogFile(logger, log_level)
    sys.stderr = sys.stdout

def revert_output_redirects():
    sys.stdout = _saved_stdouts.pop()
    sys.stderr = _saved_stderrs.pop()

def write(value, *other_values):
    """Write something to sys.stdout like the print statement would, and flush
    the buffer.
    """
    values = [value]
    values.extend(other_values)

    sys.stdout.write(" ".join("%s" % value for value in values) + "\n")
    sys.stdout.flush()

#------------------------------------------------------------------------------
# Functions to start daemon processes:

def start_python_script(file_name):
    _start_python_with_args((file_name,))

def start_python_module(module_name):
    _start_python_with_args(("-m", module_name))

def _start_python_with_args(python_args):
    command_args = [sys.executable]
    command_args.extend(python_args)
    start_detached_program(command_args)

def start_detached_program(command_args):
    # Note that, because we're using the DETACHED_PROCESS flag, it's important
    # that the process does not try to print to stdout.
    kwargs = {}
    if platform.system() == "Windows":
        DETACHED_PROCESS = 0x08
        kwargs["creationflags"] = DETACHED_PROCESS

    subprocess.Popen(command_args, **kwargs)
